/*
 * logon.cpp
 *
 *  Created on: Nov 15, 2013
 *      Author: killerg
 */

#include "logon_deps.h"
#include "logon.h"
#include "logon_cfg.h"
#include "server_session.h"
#include "client_session.h"
#include "server_mgr.h"
#include "auth_session.h"


#include "share/clock.h"
#include "share/net_s.h"
#include "share/connection_mgr.h"
#include "share/cfg_file.h"
#include "share/util.h"
#include "share/db_mgr.h"
#include "share/profiler.h"
#include "share/console2.h"
#include "share/msg_coder.h"

#include "version.h"

logon_t g_logon;

void handle_ctrl_c(int signal) {
	g_logon.svcdata->shut = true;
}

int logon_logcb(int mask, const char* fmt, ...) {
    va_list arg;
    va_start(arg, fmt);
    int n = g_console->vlog(mask, fmt, arg);
    va_end(arg);
    return n;
}
int logon_vlogcb(int mask, const char* fmt, va_list args) {
    int n = g_console->vlog(mask, fmt, args);
    return n;
}

bool logon_t::init(SvcData* svcdata_) {
    on_signal(SIGINT, handle_ctrl_c);
    sig_ignore(SIGPIPE);

    svcdata = svcdata_;
    cfg = new logon_cfg_t;
    clock = new my_clock_t;
    clisess_mgr = new clientsess_mgr_t;
    svrsess_mgr = new serversess_mgr_t;
    svrmgr = new server_mgr;
    authsess = new auth_session_t;
    console = new console_t2;

    std::string logname = fmt_cstr("logon_%s", svcdata->prefix);
    if (!console->init_log(logname.c_str())) {
    	//printf("g_console log init failed\r\n");
        return false;
    }

    util_logcb = logon_logcb;
    util_vlogcb = logon_vlogcb;

    UTIL_LOG(I, "branch:%s, commit:%s", GIT_BRANCH, GIT_COMMIT_HASH);
    UTIL_LOG(I, "start init");

    if (!console->init_net()) {
        UTIL_LOG(E, "console init net err init failed");
        return false;
    }

    if (!cfg->init(svcdata->prefix)) {
        UTIL_LOG(E, "error load logon.txt init failed");
        return false;
    }

    if (cfg->DecodeClient) {
        if (!init_code_table()) {
            UTIL_LOG(E, "code table init net err init failed");
            return false;
        }
    }

    if (!console->start_accept(
            cfg->ListenConsoleIp.c_str(),
            cfg->ListenConsolePort)) {

        UTIL_LOG(E, "listenint for console err at %s:%d init failed",
                g_cfg->ListenConsoleIp.c_str(),
                g_cfg->ListenConsolePort);
        return false;
    }
    UTIL_LOG(I, "listenint for console at %s:%d",
            g_cfg->ListenConsoleIp.c_str(),
            g_cfg->ListenConsolePort);

    if (!clock->init(1000)) {
        UTIL_LOG(E, "error init clock init failed");
        return false;
    }


    if (!authsess->init()) {
        UTIL_LOG(E, "error init authsess init failed\n");
        return false;
    }

    if (!svrsess_mgr->init()) {
        UTIL_LOG(E, "error init svrsess_mgr init failed\n");
        return false;
    }

    if (!clisess_mgr->init()) {
        UTIL_LOG(E, "error init clisess_mgr init failed\n");
        return false;
    }

    console->watch_n("run_sec", [this]()->int{ return int(clock->eclipse); });
    console->watch_n("server_num", [this]()->int{ return svrsess_mgr->connmgr.size(); });
    console->watch_n("auth_connected", [this](){ return authsess->tran.is_connected() ? 1 : 0; });
    console->watch_n("authing", [this]()->int{ return authsess->authing; });
    console->watch_n("clientfd_num", [this]()->int{ return clisess_mgr->net.cur_fdnum; });
    console->watch_n("clientsess_num", [this]()->int{ return clisess_mgr->connmgr.size(); });
    for (int i=1; i<ELSTAGENUM; ++i)
        console->watch_n(fmt_cstr("l:%s", LogonStageName[i]), [this, i]()->int{ return count[i]; });



    console->watch_f("frame_busy", [this]()->double{ return cpu_time / 5; }, [this](){return clock->tick_len;});
    console->watch_f("clisess_pct", [this]()->double{ return clisess_acc / cpu_time; }, [this](){return 1.0f;});
    console->watch_f("svrsess_pct", [this]()->double{ return svrsess_acc / cpu_time; }, [this](){return 1.0f;});
    console->watch_f("authsess_pct", [this]()->double{ return authsess_acc / cpu_time; }, [this](){return 1.0f;});
    console->watch_f("console_pct", [this]()->double{ return console_acc / cpu_time; }, [this](){return 1.0f;});

    UTIL_LOG(I, "end init");

    return true;
}

void logon_t::destroy() {
    UTIL_LOG(I, "start destroy");

    clisess_mgr->base::destroy();
    svrsess_mgr->destroy();

    authsess->destroy();

    clock->destroy();

    UTIL_LOG(I, "end destroy");

    if (cfg->DecodeClient)
        destroy_code_table();

    console->destroy();

    safe_del(svrmgr);
    safe_del(svrsess_mgr);
    safe_del(clisess_mgr);
    safe_del(authsess);
    safe_del(clock);
    safe_del(cfg);
    safe_del(console);
}

void logon_t::loop() {
    UTIL_LOG(I, "start loop");


    while (!svcdata->shut) {
        clock->begin_update();
#define TIME_BEGIN(name) double name##_begin = clock->get_time()
#define TIME_END(name) double name##_time = clock->get_time() - name##_begin; name##_acc += name##_time

        TIME_BEGIN(svrsess);
        svrsess_mgr->update(clock->delta);
        TIME_END(svrsess);

        TIME_BEGIN(clisess);
        memset(count, 0, sizeof(count));
        clisess_mgr->base::update(clock->delta);
        TIME_END(clisess);

        TIME_BEGIN(authsess);
        authsess->update();
        TIME_END(authsess);

        TIME_BEGIN(console);
        console->update();
        TIME_END(console);

        clock->end_update();
        clock->wait_frame();

        cpu_time += clock->frame_busy;
        if (clock->sec_jump) {
            console->update_watcher();
            UTIL_LOG(C, "\n%s", console->watch_ss.str().c_str());
        	svrsess_acc = 0.0f;
        	clisess_acc = 0.0f;
        	authsess_acc = 0.0f;
        	console_acc = 0.0f;
        	cpu_time = 0.0f;
        }

        svcdata->refresh = clock->tt_now;

#undef TIME_BEGIN
#undef TIME_END
    }
    UTIL_LOG(I, "end loop");

}




